package me.zhengjie.modules.management.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import com.alibaba.fastjson.JSONArray;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import me.zhengjie.domain.EmailConfig;
import me.zhengjie.domain.vo.EmailVo;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.management.domain.ConferenceRecord;
import me.zhengjie.modules.management.domain.MrRecordDtl;
import me.zhengjie.modules.management.domain.Pageable;
import me.zhengjie.modules.management.mapper.ConferenceRecordMapper;
import me.zhengjie.modules.management.mapper.ConferenceRoomMapper;
import me.zhengjie.modules.management.mapper.MrRecordDtlMapper;
import me.zhengjie.modules.management.mapper.UserMapper;
import me.zhengjie.modules.management.service.EmailDtoService;
import me.zhengjie.modules.management.service.MrRecordDtlService;
import me.zhengjie.modules.management.service.dto.*;
import me.zhengjie.modules.system.domain.User;
import me.zhengjie.modules.system.repository.UserRepository;
import me.zhengjie.service.EmailService;
import me.zhengjie.utils.PageHelpResultUtil;
import me.zhengjie.utils.SecurityUtils;
import net.bytebuddy.dynamic.scaffold.TypeWriter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * @program: eladmin
 * @description: 会议明细逻辑实现层
 * @author: ming.cao
 * @create: 2020-12-14 19:25
 **/
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true ,rollbackFor = Exception.class)
public class MrRecordDtlServiceImpl implements MrRecordDtlService {


    @Value("${file-base-url}")
    private String fileBaseUrl;

    private final MrRecordDtlMapper mrRecordDtlMapper;

    private final EmailService emailService;

    private final ConferenceRecordMapper conferenceRecordMapper;

    private final UserMapper userMapper;

    private final EmailDtoService emailDtoService;

    private final ConferenceRoomMapper conferenceRoomMapper;

    // 会议室计费开启时间
    private final static int startHour = 7;
    // 会议室计费关闭时间
    // 只在此时间内计费
    private final static int endHour = 22;

    // 会议室价格/每小时
    //private final static BigDecimal moneyPerHour = BigDecimal.valueOf(40.0);

    @Override
    public Map<String,Object> getListById(Integer recordId, Pageable pageable) {
        if (pageable.getPage()==-1){
            Map<String,Object> map = new LinkedHashMap<>(2);
            List<MrRecordDtlDto> list = mrRecordDtlMapper.getListById(recordId);
            map.put("content",list);
            map.put("totalElements",list.size());
            return map;
        }else{
            PageHelper.startPage(pageable.getPage(),pageable.getSize());
            List<MrRecordDtlDto> list = mrRecordDtlMapper.getListById(recordId);
            //数据分页
            PageInfo<MrRecordDtlDto> pageInfo1 = new PageInfo<>(list);
            return PageHelpResultUtil.toPage(pageInfo1);
        }

    }

    @Override
    public void addMrRecordDtl(MrRecordDtl dtl) {
        MrRecordDtlDto mrRecordDtlDto = mrRecordDtlMapper.findTypeId(dtl.getMaterialId());
        //获取传过来物资的种类,如果type是1，判断number是否是0.5的倍数,如果type是0，判断是否是正整数
           if(mrRecordDtlDto.getTypeId()==1){
               if(dtl.getNumber().doubleValue()%0.5!=0){
                   throw new BadRequestException("时长请以半个小时为单位！");
               }
           }else{
               boolean result=dtl.getNumber().toString().matches("[0-9]+$");
               if(result==false){
                   throw new BadRequestException("请输入整数数量！");
               }
           }
            dtl.setCreateDateTime(new Timestamp(new Date().getTime()));
            dtl.setCreateUserId(SecurityUtils.getCurrentUsername());
            mrRecordDtlMapper.addMrRecordDtl(dtl);
    }

    @Override
    public void updateMrRecordDtl(MrRecordDtl dtl){
        try {
            dtl.setModifyDateTime(new Timestamp(new Date().getTime()));
            dtl.setModifyUserId(SecurityUtils.getCurrentUsername());
            mrRecordDtlMapper.updateMrRecordDtl(dtl);
        }catch (Exception e){
            throw new BadRequestException("修改失败！");
        }
    }

    @Override
    @Transactional
    public void delMrRecordDtl(List<Integer> ids) {
        try{
            for (Integer id : ids) {
                mrRecordDtlMapper.delMrRecordDtl(id);
            }
        }catch (Exception e){
            throw new BadRequestException("删除失败！");
        }
    }

    /**
     * 结算
     */
    @Override
    @Transactional
    public void settle(ConferenceRecord record) {
        long endTime = record.getEndDate().getTime();
        Date date = new Date(endTime);
        if(date.after(new Date())){
            throw new BadRequestException("请等待会议结束后再进行结算！");
        }else{

            Timestamp endDate = record.getEndDate();
            Timestamp beginDate = record.getBeginDate();
            if(endDate.after(beginDate)){
                //获取此教室下一个会议开始时间，如果结束时间改了大于之后会议的开始时间的，抛异常
                List<Timestamp> nextBegainTime = conferenceRecordMapper.findNextBegainTime(record);
                if(nextBegainTime.size()>0){
                    Timestamp min = Collections.min(nextBegainTime);
                    if(endDate.getTime()>min.getTime()){
                        throw new BadRequestException("结束时间超出下个会议的开始时间！");
                    }else{
                        //1、变更结束时间
                        mrRecordDtlMapper.updateRecordDate(record);
                        //2、结算
                        //获取材料费
                        BigDecimal materialsCost = mrRecordDtlMapper.getMaterialCost(record.getRecordId());
                        //获取会议室费
                        BigDecimal roomCost = mrRecordDtlMapper.getRoomCost(record.getRecordId());

                        //更新值
                        record.setMaterialsCost(materialsCost);
                        record.setRoomCost(roomCost);
                        //设置结算状态
                        record.setStatus(7);
                        record.setModifyDateTime(new Timestamp(new Date().getTime()));
                        record.setModifyUserId(SecurityUtils.getCurrentUsername());


                        mrRecordDtlMapper.updateRecord(record);
                    }
                }else{
                    //1、变更结束时间
                    mrRecordDtlMapper.updateRecordDate(record);
                    //2、结算
                    //获取材料费
                    BigDecimal materialsCost = mrRecordDtlMapper.getMaterialCost(record.getRecordId());
                    //获取会议室费
                    BigDecimal roomCost = mrRecordDtlMapper.getRoomCost(record.getRecordId());

                    //更新值
                    record.setMaterialsCost(materialsCost);
                    record.setRoomCost(roomCost);
                    //设置结算状态
                    record.setStatus(7);
                    record.setModifyDateTime(new Timestamp(new Date().getTime()));
                    record.setModifyUserId(SecurityUtils.getCurrentUsername());


                    mrRecordDtlMapper.updateRecord(record);
                }

            }else{
                throw new BadRequestException("会议结束时间不能小于开始时间！");
            }

//*****************************************************************************************

            //根据record_id获取申请人的邮箱
            String email = userMapper.findEmailById(conferenceRecordMapper.findApplicantIdByRecordId(record.getRecordId()));
            //获取邮件信息
            EmailDto emailDto = emailDtoService.getEmailDto(record.getRecordId());
            //System.out.println(email);
            //3、如果邮箱不为空，发送邮件(未完成)
            if (ObjectUtil.isNotEmpty(email)) {
                sendEmail(email,emailDto);
            }
        }

    }

    @Override
    public Map<String, Object> getCurrentRoomCost(RoomCostCriteria criteria) {
        //判断传过来的时间是否比开始时间小
        List<RecordDto> recordDtoList = conferenceRecordMapper.findById(criteria.getRecordId());
        Timestamp beginDate = recordDtoList.get(0).getBeginDate();
        if(criteria.getEndDate().before(beginDate)){
            throw new BadRequestException("结束时间不能比开始时间小！");
        }


        //获取会议室费
        BigDecimal roomCost = mrRecordDtlMapper.getCurrentRoomCost(criteria);


        /*LocalDateTime startTime=  recordDtoList.get(0).getBeginDate().toLocalDateTime();
        LocalDateTime endTime;
        if (ObjectUtil.isNotEmpty(criteria.getEndDate())){

             endTime= criteria.getEndDate().toLocalDateTime();
        }else {
             endTime = recordDtoList.get(0).getEndDate().toLocalDateTime();
        }
         BigDecimal moneyPerHour = conferenceRoomMapper.findCostById(recordDtoList.get(0).getRoomId());
         BigDecimal cost=  getMoney(startTime,endTime,moneyPerHour);*/



        Map<String,Object> map = new LinkedHashMap<>(2);
        map.put("roomCost",roomCost);
        return map;
    }

    /**
     * 结算邮件初始化
     * @return
     */
    public void sendEmail(String email,EmailDto emailDto){
        EmailVo emailVo = new EmailVo();
        emailVo.setSubject("大学教室管理系统");
        Map<String, Object> data = new HashMap<>(16);
        data.put("trainingName",emailDto.getSubject());
        data.put("address",emailDto.getRoomName());
        data.put("type",emailDto.getTypeName());
        data.put("numberOfPeople",emailDto.getUserNumber());
        data.put("MaterialCost",emailDto.getMaterialCost());
        data.put("RoomCost",emailDto.getRoomCost());
        data.put("beginTime",emailDto.getBeginDate());
        data.put("endTime",emailDto.getEndDate());
        data.put("applicant",emailDto.getApplicant());
        data.put("dept",emailDto.getApplicantDept());
        List<MrRecordDtlDto> materialDtl=emailDto.getMaterialDtl();
        data.put("materialDtl",materialDtl);
        TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));
        Template template = engine.getTemplate("email/settleEmail.ftl");
        emailVo.setContent(template.render(data));

        //List<String> emails = Arrays.asList(quartzJob.getEmail().split("[,，]"));
        List<String> emails = new ArrayList<String>();
        emails.add(email);
        emailVo.setTos(emails);
        EmailConfig emailConfig = emailService.find();
        System.out.println(emailConfig.toString());
        emailService.send(emailVo,emailConfig);
    }


    /**
     * @Author MrNiurh
     * @Date Creat in 2020/12/22
     * @Description 会议室计费
     * @See <a href="https://github.com/MrNiurh?tab=repositories">github</a>
     */

        /**
         * 计算会议室收费
         * BigDecimal 处理精度问题
         *
         * @return BigDecimal
         */
        private static BigDecimal getMoney(LocalDateTime startTime,LocalDateTime endTime,BigDecimal moneyPerHour) {

            LocalDate s = startTime.toLocalDate();
            LocalDate e = endTime.toLocalDate();
            // 计算日期差
            long days = s.until(e, ChronoUnit.DAYS);

            // 计算日期差
            Duration duration = Duration.between(startTime, endTime);
            //long days = duration.toDays();

            if (duration.toMinutes() < 0) {
                System.err.println("会议结束时间不能早于开始时间");
                return null;
            }

            // 开始 & 结束 时间的时间点（小时）
            int start = startTime.getHour();
            int end = endTime.getHour();

            int startMinute = startTime.getMinute();
            int endMinute = endTime.getMinute();



            // 时间转换
            BigDecimal realStart = timeTransfer(start, startMinute);
            BigDecimal realEnd = timeTransfer(end, endMinute);

            /**
             * 总时间合计
             * (realEnd - realStart) + days * (endHour - startHour)
             */
            BigDecimal totalHours = realEnd.subtract(realStart)
                    .add(BigDecimal.valueOf(days)
                            .multiply(BigDecimal.valueOf(endHour).subtract(BigDecimal.valueOf(startHour))));
            System.err.println(moneyPerHour);
            System.err.println(totalHours);
            /**
             * 价格计算
             * totalHours * moneyPerHour
             */
            BigDecimal totalMoney = totalHours.multiply(moneyPerHour);
            System.err.println("total:"+totalMoney);

            // 将时间内的 T 去掉
            System.out.println("会议开始时间： " + startTime.toString().replace("T", " "));
            System.out.println("会议结束时间 " + endTime.toString().replace("T", " "));
            System.out.println("会议总耗时：" + totalHours + "h");
            System.out.println("会议室价格：" + moneyPerHour + "￥/h");
            System.out.println("总计：" + totalMoney + "元");
            // 返回价格
            return totalMoney;
        }

        /**
         * 将时间转换为正常范围
         * 小于计费开启时间记为开启时间
         * 大于计费关闭时间记为关闭时间
         *
         * @param time
         * @return BigDecimal
         */
        private static BigDecimal timeTransfer(int time, int minute) {
            if (time < startHour) {
                return BigDecimal.valueOf(startHour);
            }
            if (time >= endHour) {
                return BigDecimal.valueOf(endHour);
            } else {
                /**
                 * time + minute/60.0
                 */
                return BigDecimal.valueOf(time).add(BigDecimal.valueOf(minute).divide(BigDecimal.valueOf(60.0)));
            }
        }


}
